<template>
  <div>
    <a-trigger trigger="click" :unmount-on-close="false">
      <a-button :style="{backgroundColor: color,border: '1px solid #c6c6c6'}">
        <template #icon>
          <icon-down style="color: #ffffff" />
        </template>
      </a-button>
      <template #content>
        <div class="color-select" :style="{width: props.width}">
          <div ref="saturationValueRef" class="saturation-value" @mousedown="mousedownSV">
            <div :style="`background-color: hsl(${hue}, 100%, 50%);`">
              <div class="point" :style="pointStyle"></div>
            </div>
            <div class="saturation-value-2"></div>
            <div class="saturation-value-3"></div>
          </div>
          <div class="color-select-middle">
            <div style="flex: auto">
              <div ref="hueSliderRef" class="hue-slider" @mousedown="mousedownHue">
                <div class="slider" :style="hueSliderStyle"></div>
              </div>
              <div ref="alphaSliderRef" class="alpha-slider" @mousedown="mousedownAlpha">
                <div class="slider" :style="alphaSliderStyle"></div>
                <div :style="`background: linear-gradient(to right, rgba(0,0,0,0), ${colorObj.rgb});width: 100%;height: 100%`"></div>
              </div>
            </div>
            <div class="color-diamond">
              <div :style="`background-color: ${colorObj.rgba};width: 100%;height: 100%;box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15), inset 0 0 4px rgba(0, 0, 0, .25);`"></div>
            </div>
          </div>
          <div class="color-value">
            <div class="hex">
              <label>
                <input :value="colorObj.hex8" @input="hexChange" spellcheck="false"/>
              </label>
              <p>HEXA</p>
            </div>
            <div class="rgba-r">
              <label>
                <input :value="red" @input="redChange"/>
              </label>
              <p>R</p>
            </div>
            <div class="rgba-g">
              <label>
                <input :value="green" @input="greenChange"/>
              </label>
              <p>G</p>
            </div>
            <div class="rgba-b">
              <label>
                <input :value="blue" @input="blueChange"/>
              </label>
              <p>B</p>
            </div>
            <div class="rgba-a">
              <label>
                <input :value="alpha" @input="alphaChange"/>
              </label>
              <p>A</p>
            </div>
          </div>
          <ul class="preset">
            <li v-for="(item, index) in presets" :key="index" :style="`cursor: pointer; background-color: ${item}`" @click="presetChange(item)"></li>
          </ul>
        </div>
      </template>
    </a-trigger>
  </div>
</template>

<script lang="ts" setup>
  import { ref, watch, computed, onMounted } from 'vue';

  const props = defineProps({
    width: {
      type: String,
      default: '100%',
    },
    color: {
      type: Object || String,
      default() {
        return {
          r: 217,
          g: 128,
          b: 95,
          a: 1,
        };
      },
    },
    // 预设颜色
    presets: {
      type: Array,
      default() {
        return [
          '#FF4500FF',
          '#8B572AFF',
          '#FA8C16FF',
          '#F5A623FF',
          '#FADB14FF',
          '#F8E71CFF',
          '#8BBB11FF',
          '#417505FF',
          '#B8E986FF',
          '#7ED321FF',
          '#52C41AFF',
          '#90EE90FF',
          '#50E3C2FF',
          '#13A8A8FF',
          '#4A90E2FF',
          '#1677FFFF',
          '#2F54EBFF',
          '#722ED1FF',
          '#9013FEFF',
          '#BD10E0FF',
          '#EB2F96FF',
          '#D0021BFF',
          '#F5222DFF',
          '#000000FF',
          '#4A4A4AFF',
          '#9B9B9BFF',
          '#FFFFFFFF',
        ];
      },
    },
  });
  const emit = defineEmits(['update:color']);

  const saturationValueRef = ref();
  const hueSliderRef = ref();
  const alphaSliderRef = ref();
  const pointStyle = ref('top: 25%;left: 80%;');
  const hueSliderStyle = ref('left: 0;');
  const alphaSliderStyle = ref('left: calc(100% - 6px);');
  const hue = ref(0);
  const saturation = ref(1);
  const value = ref(1);
  const red = ref(255);
  const green = ref(0);
  const blue = ref(0);
  const alpha = ref(1);
  // const hexa = ref<string>('');

  const rgb2hsv = (r: any, g: any, b: any) => {
    const r1 = r / 255;
    const g1 = g / 255;
    const b1 = b / 255;
    const max = Math.max(r1, g1, b1);
    const min = Math.min(r1, g1, b1);
    const d = max - min;
    let h = 0;
    let s = 0;
    let v = 0;
    if (d === 0) {
      h = 0;
    } else if (max === r1) {
      h = ((60 * (g1 - b1)) / d + 360) % 360;
    } else if (max === g1) {
      h = 60 * ((b1 - r1) / d + 2);
    } else if (max === b1) {
      h = 60 * ((r1 - g1) / d + 4);
    }
    if (max === 0) {
      s = 0;
    } else {
      s = d / max;
    }
    v = max;
    h = Math.floor(h + 0.5);
    s = Math.floor(s * 100 + 0.5) / 100;
    v = Math.floor(v * 100 + 0.5) / 100;
    return { h, s, v };
  };
  const hsv2rgb = (h: any, s: any, v: any) => {
    if (h === 360) {
      h = 0;
    }
    const i = Math.floor(h / 60) % 6;
    const f = h / 60 - i;
    const p = v * (1 - s);
    const q = v * (1 - s * f);
    const t = v * (1 - s * (1 - f));
    let r = 0;
    let g = 0;
    let b = 0;
    if (i === 0) {
      r = v;
      g = t;
      b = p;
    } else if (i === 1) {
      r = q;
      g = v;
      b = p;
    } else if (i === 2) {
      r = p;
      g = v;
      b = t;
    } else if (i === 3) {
      r = p;
      g = q;
      b = v;
    } else if (i === 4) {
      r = t;
      g = p;
      b = v;
    } else if (i === 5) {
      r = v;
      g = p;
      b = q;
    }
    r = Math.floor(r * 255 + 0.5);
    g = Math.floor(g * 255 + 0.5);
    b = Math.floor(b * 255 + 0.5);
    return { r, g, b };
  };
  const rgba2hex = (r: any, g: any, b: any, a: any = 1) => {
    r = parseInt(r, 10);
    g = parseInt(g, 10);
    b = parseInt(b, 10);
    a = parseFloat(a);
    let r1 = '';
    let g1 = '';
    let b1 = '';
    let a1 = 'FF';
    if (r.toString(16).length !== 2) {
      r1 = `0${r.toString(16)}`;
    } else {
      r1 = r.toString(16);
    }
    if (g.toString(16).length !== 2) {
      g1 = `0${g.toString(16)}`;
    } else {
      g1 = g.toString(16);
    }
    if (b.toString(16).length !== 2) {
      b1 = `0${b.toString(16)}`;
    } else {
      b1 = b.toString(16);
    }
    if (a !== 1) {
      const aTemp = Math.floor(256 * a);
      if (aTemp.toString(16).length !== 2) {
        a1 = `0${aTemp.toString(16)}`;
      } else {
        a1 = aTemp.toString(16);
      }
    }
    return `#${r1}${g1}${b1}${a1}`.toUpperCase();
  };
  const hex2rgba = (s: any) => {
    let a = 1;
    let b = 0;
    let g = 0;
    let r = 0;
    if (/^#?[0-9a-fA-F]{3}$/.test(s)) {
      b = s.substring(s.length - 1, s.length);
      g = s.substring(s.length - 2, s.length - 1);
      r = s.substring(s.length - 3, s.length - 2);
      // return hex2rgba(`${r + r}${g + g}${b + b}`);
      const rgba: any = hex2rgba(`${r + r}${g + g}${b + b}`);
      r = rgba.r;
      g = rgba.g;
      b = rgba.b;
      a = rgba.a;
      return { r, g, b, a };
    }
    if (/^#?[0-9a-fA-F]{4}$/.test(s)) {
      a = s.substring(s.length - 1, s.length);
      b = s.substring(s.length - 2, s.length - 1);
      g = s.substring(s.length - 3, s.length - 2);
      r = s.substring(s.length - 4, s.length - 3);
      // return hex2rgba(`${r + r}${g + g}${b + b}${a + a}`);
      const rgba: any = hex2rgba(`${r + r}${g + g}${b + b}${a + a}`);
      r = rgba.r;
      g = rgba.g;
      b = rgba.b;
      a = rgba.a;
      return { r, g, b, a };
    }
    if (/^#?[0-9a-fA-F]{6}$/.test(s)) {
      b = parseInt(`0x${s.substring(s.length - 2, s.length)}`, 16);
      g = parseInt(`0x${s.substring(s.length - 4, s.length - 2)}`, 16);
      r = parseInt(`0x${s.substring(s.length - 6, s.length - 4)}`, 16);
    }
    if (/^#?[0-9a-fA-F]{8}$/.test(s)) {
      a = parseInt(`0x${s.substring(s.length - 2, s.length)}`, 16) / 255;
      b = parseInt(`0x${s.substring(s.length - 4, s.length - 2)}`, 16);
      g = parseInt(`0x${s.substring(s.length - 6, s.length - 4)}`, 16);
      r = parseInt(`0x${s.substring(s.length - 8, s.length - 6)}`, 16);
    }
    return { r, g, b, a };
  };
  // 解析输入的数据,只能解析hex颜色和rgb对象形式的数据
  const parseColor = (color: any) => {
    let r = 255;
    let g = 255;
    let b = 255;
    let a = 1;
    if (color) {
      if (typeof color === 'string') {
        if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8}|[0-9a-fA-F]{3}|[0-9a-fA-F]{4})$/.test(color)) {
          return hex2rgba(color);
        }
      } else {
        if (color.r > 255) {
          r = 255;
        } else if (color.r < 0) {
          r = 0;
        } else {
          r = color.r;
        }
        if (color.g > 255) {
          g = 255;
        } else if (color.g < 0) {
          g = 0;
        } else {
          g = color.g;
        }
        if (color.b > 255) {
          b = 255;
        } else if (color.b < 0) {
          b = 0;
        } else {
          b = color.b;
        }
        if (color.a > 1) {
          a = 1;
        } else if (color.a < 0) {
          a = 0;
        } else {
          a = color.a;
        }
      }
    }
    return { r, g, b, a };
  };

  watch([red, green, blue], (newValue) => {
    emit('update:color', {
      rgb: {r: red.value, g: green.value, b: blue.value},
      rgba: {r: red.value, g: green.value, b: blue.value, a: alpha.value},
      hex6: rgba2hex(red.value, green.value, blue.value),
      hex8: rgba2hex(red.value, green.value, blue.value, alpha.value),
    });
    const { h, s, v } = rgb2hsv(red.value, green.value, blue.value);
    hue.value = h;
    saturation.value = s;
    value.value = v;
    // 移动背景板圆圈
    pointStyle.value = `top: ${100 - v * 100}%;left: ${s * 100}%;`;
    // 移动色调滑块
    hueSliderStyle.value = `left: ${(hue.value / 360) * 100}%;`;
  });
  watch(alpha, () => {
    emit('update:color', {
      rgb: {r: red.value, g: green.value, b: blue.value},
      rgba: {r: red.value, g: green.value, b: blue.value, a: alpha.value},
      hex6: rgba2hex(red.value, green.value, blue.value),
      hex8: rgba2hex(red.value, green.value, blue.value, alpha.value),
    });
    // 移动透明度滑块
    if (alpha.value > 1) {
      alphaSliderStyle.value = 'left: "calc(100% - 6px)";';
    } else {
      alphaSliderStyle.value = `left: ${alpha.value * 100}%;`;
    }
  });

  const colorObj = computed(() => {
    // hex.value = String(props.color);
    const r = red.value;
    const g = green.value;
    const b = blue.value;
    const a = alpha.value;
    const h = hue.value;
    const s = saturation.value;
    const v = value.value;
    return {
      rgb: `rgba(${r},${g},${b})`,
      rgba: `rgba(${r},${g},${b},${a})`,
      hex6: rgba2hex(r, g, b),
      hex8: rgba2hex(r, g, b, a),
      hsv: `hsv(${h},${s},${v})`,
      hsl: ``,
    };
  });

  // 输入框值变化,限制输入的值
  const hexChange = (e: any) => {
    const v = e.target.value;
    if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(v)) {
      const { r, g, b, a } = hex2rgba(v);
      red.value = r;
      green.value = g;
      blue.value = b;
      alpha.value = a;
    }
  };
  const redChange = (e: any) => {
    const v = e.target.value;
    if (v !== '') {
      if (v > 255) {
        red.value = 255;
      }
      if (v < 0) {
        red.value = 0;
      }
      if (v >= 0 && v <= 255) {
        red.value = parseInt(v, 10);
      }
      if (!Number(v)) {
        red.value = 0;
      }
    }
  };
  const greenChange = (e: any) => {
    const v = e.target.value;
    if (v !== '') {
      if (v > 255) {
        green.value = 255;
      }
      if (v < 0) {
        green.value = 0;
      }
      if (v >= 0 && v <= 255) {
        green.value = parseInt(v, 10);
      }
      if (!Number(v)) {
        red.value = 0;
      }
    }
  };
  const blueChange = (e: any) => {
    const v = e.target.value;
    if (v !== '') {
      if (v > 255) {
        blue.value = 255;
      }
      if (v < 0) {
        blue.value = 0;
      }
      if (v >= 0 && v <= 255) {
        blue.value = parseInt(v, 10);
      }
      if (!Number(v)) {
        red.value = 0;
      }
    }
  };
  const alphaChange = (e: any) => {
    let v = e.target.value;
    if (v !== '') {
      v = parseFloat(v);
      alpha.value = v;
      if (v > 1) {
        alpha.value = 1;
      }
      if (v < 0) {
        alpha.value = 0;
      }
      if (v >= 0 && v <= 1) {
        alpha.value = v;
      }
      if (!Number(v)) {
        red.value = 1;
      }
    }
  };
  // 点击预设方块事件
  const presetChange = (item: any) => {
    if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(item)) {
      const { r, g, b, a } = hex2rgba(item);
      red.value = r;
      green.value = g;
      blue.value = b;
      alpha.value = a;
    }
  };
  // 饱和度和亮度
  const handleChangeSV = (e: any) => {
    const w = saturationValueRef.value.clientWidth;
    const h = saturationValueRef.value.clientHeight;
    let x = e.pageX - saturationValueRef.value.getBoundingClientRect().left;
    let y = e.pageY - saturationValueRef.value.getBoundingClientRect().top;
    if (x < w && x > 0) {
      //
    } else if (x > w) {
      x = w;
    } else {
      x = 0;
    }
    if (y < h && y > 0) {
      //
    } else if (y > h) {
      y = h;
    } else {
      y = 0;
    }
    // 计算饱和度和亮度
    saturation.value = Math.floor((x / w) * 100 + 0.5) / 100;
    value.value = Math.floor((1 - y / h) * 100 + 0.5) / 100;
    // hsv转化为rgb
    const { r, g, b } = hsv2rgb(hue.value, saturation.value, value.value);
    red.value = r;
    green.value = g;
    blue.value = b;
    // 移动背景板圆圈
    pointStyle.value = `top: ${y}px;left: ${x}px;`;
  };
  const mouseupSV = (e: any) => {
    // 鼠标松开后移除事件
    window.removeEventListener('mousemove', handleChangeSV);
    window.removeEventListener('mouseup', mouseupSV);
  };
  const mousedownSV = (e: any) => {
    // 鼠标按下计算饱和度和亮度并添加事件
    handleChangeSV(e);
    // 添加整个页面的鼠标事件
    window.addEventListener('mousemove', handleChangeSV);
    window.addEventListener('mouseup', mouseupSV);
  };
  // 色调
  const handleChangeHue = (e: any) => {
    const w = hueSliderRef.value.clientWidth;
    let x = e.pageX - saturationValueRef.value.getBoundingClientRect().left;
    if (x < w && x > 0) {
      //
    } else if (x > w) {
      x = w;
    } else {
      x = 0;
    }
    // 计算色调
    hue.value = Math.floor((x / w) * 360 + 0.5);
    // hsv转化为rgb
    const { r, g, b } = hsv2rgb(hue.value, saturation.value, value.value);
    red.value = r;
    green.value = g;
    blue.value = b;
    // 移动滑块
    if (x >= (w - 6)) {
      hueSliderStyle.value = `left: ${w - 6}px;`;
    } else {
      hueSliderStyle.value = `left: ${x}px;`;
    }
  };
  const mouseupHue = (e: any) => {
    window.removeEventListener('mousemove', handleChangeHue);
    window.removeEventListener('mouseup', mouseupHue);
  };
  const mousedownHue = (e: any) => {
    handleChangeHue(e);
    window.addEventListener('mousemove', handleChangeHue);
    window.addEventListener('mouseup', mouseupHue);
  };
  // 透明度
  const handleChangeAlpha = (e: any) => {
    const w = alphaSliderRef.value.clientWidth;
    let x = e.pageX - saturationValueRef.value.getBoundingClientRect().left;
    if (x < w && x > 0) {
      //
    } else if (x > w) {
      x = w;
    } else {
      x = 0;
    }
    // 计算透明度
    alpha.value = Math.floor((x / w) * 100 + 0.5) / 100;
    // 移动滑块
    if (x >= w - 6) {
      alphaSliderStyle.value = `left: ${w - 6}px;`;
    } else {
      alphaSliderStyle.value = `left: ${x}px;`;
    }
  };
  const mouseupAlpha = (e: any) => {
    window.removeEventListener('mousemove', handleChangeAlpha);
    window.removeEventListener('mouseup', mouseupAlpha);
  };
  const mousedownAlpha = (e: any) => {
    handleChangeAlpha(e);
    window.addEventListener('mousemove', handleChangeAlpha);
    window.addEventListener('mouseup', mouseupAlpha);
  };

  onMounted(() => {
    const { r, g, b, a } = parseColor(props.color);
    red.value = r;
    green.value = g;
    blue.value = b;
    alpha.value = a;
  });
</script>

<style lang="less" scoped>
  .color-select {
    position: relative;
    user-select: none;
    /*width: 100%;*/
    background: #fff;
    padding: 10px;
    /*border: 1px solid #ccc;*/
    box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
    border-radius: 4px;
  }
  /* 饱和度和亮度 */
  .saturation-value {
    cursor: pointer;
    width: 100%;
    height: 200px;
    position: relative;
    margin-bottom: 10px;
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
  }
  .saturation-value > div {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
  /* 圆圈 */
  .point {
    box-sizing: border-box;
    width: 6px;
    height: 6px;
    background-color: transparent;
    border: 2px solid #ccc;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    position: absolute;
    z-index: 9;
  }
  .saturation-value-2 {
    background: linear-gradient(to right, white, #ffffff00);
  }
  .saturation-value-3 {
    background: linear-gradient(to top, black, #ffffff00);
  }
  /* 色调 透明度 */
  .color-select-middle {
    width: 100%;
    display: flex;
    margin-bottom: 10px;
  }
  /* 色调滑块条 */
  .hue-slider {
    position: relative;
    margin-bottom: 6px;
    height: 10px;
    background: linear-gradient(90deg, red 0, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, red);
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
  }
  /* 透明度滑块条 */
  .alpha-slider {
    position: relative;
    height: 10px;
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
    background: #fff url("");
    background-size: 10px 10px;
  }
  /* 滑块 */
  .slider {
    position: absolute;
    box-shadow: 0 0 2px rgba(0, 0, 0, .6);
    box-sizing: border-box;
    width: 6px;
    height: 100%;
    background-color: #fff;
  }
  /* 颜色方块 */
  .color-diamond {
    position: relative;
    margin-left: 5px;
    width: 26px;
    height: 26px;
    border-radius: 3px;
    overflow: hidden;
    background-image: url("");
    background-size: 10px 10px;
  }
  /* 颜色的值 hex rgba */
  .color-value {
    width: 100%;
    display: flex;
    justify-content: space-between;
  }
  .color-value div {
    padding: 0 3px;
    text-align: center;
  }
  .color-value input {
    font-size: 12px;
    box-sizing: border-box;
    width: 34px;
    height: 24px;
    padding: 0;
    margin: 0;
    outline: none;
    text-align: center;
    border-radius: 3px;
    border: 1px solid #ccc;
  }
  .color-value p {
    font-size: 12px;
    margin: 3px 0 0;
  }
  .color-value .rgba-a {
    padding-right: 0;
  }
  .color-value .hex {
    flex: 1;
    padding-left: 0;
  }
  .color-value .hex input {
    width: 100%;
    height: 24px;
  }
  /* 预设颜色  */
  .preset {
    width: 100%;
    padding: 0;
    margin: 10px 0 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
  }
  .preset li {
    width: 20px;
    height: 20px;
    margin-right: 6px;
    margin-bottom: 6px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }
</style>